/*
 * BSM6.0
 *
 * Copyright 2012-2013 (C) SINODATA CO., LTD. All Rights Reserved.
 */
package com.sinodata.bsm.center.engine.resource.find;

import java.util.ArrayList;
import java.util.List;

import com.sinodata.bsm.center.bean.ResTypeBean;
import com.sinodata.bsm.center.cache.AttributeCache;
import com.sinodata.bsm.center.cache.ResAttrValCache;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.vo.Attribute;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.common.vo.ResAttrVal;

/**
 * <p>
 * Description:
 * </p>
 * 
 * @author tangli
 * @version 1.0
 * 
 * <p>
 * History:
 * 
 * Date Author Version Description
 * ---------------------------------------------------------------------------------
 * 2012-5-25 下午5:04:43 tangli 1.0 To create
 * </p>
 * 
 * @since
 * @see
 */
public class FindResBean {
    public final static int CHANGE_ADD = 1;
    public final static int CHANGE_DEL = 2;
    public final static int CHANGE_MOD = 3;
    private Res res;
    private FindResBean parent;
    private boolean changed = false;
    private int changeType;
    private final List<FindResBean> children = new ArrayList<FindResBean>();
    private final List<ResAttrVal> changeAttrValues = new ArrayList<ResAttrVal>();

    private final AttributeCache attributeCache = SpringContextHolder.getBean(AttributeCache.class);
    private final ResAttrValCache resAttrValCache = SpringContextHolder.getBean(ResAttrValCache.class);

    /**
     * 
     */
    public FindResBean() {
    }

    public Res getRes() {
        return res;
    }

    public void setRes(Res res) {
        this.res = res;
    }

    public FindResBean getParent() {
        return parent;
    }

    public void setParent(FindResBean parent) {
        this.parent = parent;
    }

    public boolean isChanged() {
        return changed;
    }

    public void setChanged(boolean changed) {
        this.changed = changed;
    }

    public int getChangeType() {
        return changeType;
    }

    public void setChangeType(int changeType) {
        this.changeType = changeType;
    }

    public void addChild(FindResBean child) {
        this.children.add(child);
    }

    public List<FindResBean> getChildren() {
        return children;
    }

    public List<ResAttrVal> getChangeAttrValues() {
        return changeAttrValues;
    }

    public String attributeValue(Long attrId) {
        for (ResAttrVal attrVal : changeAttrValues) {
            if (attrVal.getAttrId().equals(attrId)) {
                return attrVal.getAttrValue();
            }
        }
        if (res.getId() != null) {
            ResAttrVal val = resAttrValCache.get(res.getId(), attrId);
            if (val != null) {
                return val.getAttrValue();
            }
        }
        if (parent == null) {
            return null;
        } else {
            return parent.attributeValue(attrId);
        }
    }

    public void checkChange(String[] result, String argAttr) {
        List<Attribute> attributes = getAttributes(this.res.getResTypeId(), argAttr);
        if (attributes.size() != result.length - 3) {
            return;
        }

        int index = 3;
        for (Attribute attr : attributes) {
            Long resId = res.getId();
            Long attrId = attr.getId();
            ResAttrVal val = resAttrValCache.get(resId, attrId);
            if (val == null || val.getAttrValue() == null || !val.getAttrValue().equals(result[index])) {
                ResAttrVal change = new ResAttrVal();
                change.setAttrId(attrId);
                change.setAttrValue(result[index]);
                this.changeAttrValues.add(change);
            }
            index++;
        }
        if (changeAttrValues.size() > 0) {
            this.changed = true;
            this.changeType = CHANGE_MOD;
        }
    }

    public void checkChange(String[] result) {
        List<FindResBean> brothers = new ArrayList<FindResBean>();
        for (FindResBean m : children) {
            if (m.getRes().getResTypeId().equals(Long.valueOf(result[3]))) {
                brothers.add(m);
            }
        }

        List<Attribute> attributes = getAttributes(Long.valueOf(result[3]), null);

        if (attributes.size() == result.length - 4) {
            String internalId = result[0];
            FindResBean existed = null;
            for (FindResBean m : brothers) {
                if (m.getRes().getInternalId().equals(internalId)) {
                    existed = m;
                    break;
                }
            }
            if (existed == null) {// new

                FindResBean member = new FindResBean();
                member.setParent(this);
                member.setChanged(true);
                member.setChangeType(CHANGE_ADD);
                Res newRes = new Res();
                newRes.setInternalId(internalId);
                newRes.setName(result[1]);
                newRes.setDesc(result[2]);
                newRes.setResTypeId(Long.valueOf(result[3]));
                newRes.setIp(this.getRes().getIp());
                newRes.setProbeId(this.getRes().getProbeId());
                member.setRes(newRes);
                int index = 4;
                for (Attribute attr : attributes) {
                    Long attrId = attr.getId();
                    ResAttrVal change = new ResAttrVal();
                    change.setAttrId(attrId);
                    change.setAttrValue(result[index]);
                    member.getChangeAttrValues().add(change);
                    index++;
                }
                children.add(member);

            } else {// modify, existed is not null
                Long resId = existed.getRes().getId();
                int index = 4;
                for (Attribute attr : attributes) {
                    Long attrId = attr.getId();
                    ResAttrVal val = resAttrValCache.get(resId, attrId);
                    if (val == null || val.getAttrValue() == null || (val.getAttrValue() != null && !val.getAttrValue().equals(result[index]))) {
                        ResAttrVal change = new ResAttrVal();
                        change.setAttrId(attrId);
                        change.setAttrValue(result[index]);
                        existed.getChangeAttrValues().add(change);
                    }
                    index++;
                }
                if (existed.getChangeAttrValues().size() > 0) {
                    existed.setChanged(true);
                    existed.setChangeType(CHANGE_MOD);
                }
            }
        }
    }

    public void checkChange(List<String[]> results, String argAttr, Long resTypeId) {
        List<FindResBean> brothers = new ArrayList<FindResBean>();
        for (FindResBean m : children) {
            if (m.getRes().getResTypeId().equals(resTypeId)) {
                brothers.add(m);
            }
        }
        List<Attribute> attributes = getAttributes(resTypeId, argAttr);
        for (String[] result : results) {
            if (attributes.size() != result.length - 3) {
                continue;
            }
            String internalId = result[0];
            FindResBean existed = null;
            for (FindResBean m : brothers) {
                if (m.getRes().getInternalId().equals(internalId)) {
                    existed = m;
                    break;
                }
            }
            if (existed == null) {// new
                FindResBean member = new FindResBean();
                member.setParent(this);
                member.setChanged(true);
                member.setChangeType(CHANGE_ADD);
                Res newRes = new Res();
                newRes.setInternalId(internalId);
                newRes.setName(result[1]);
                newRes.setDesc(result[2]);
                newRes.setResTypeId(resTypeId);
                newRes.setIp(this.getRes().getIp());
                newRes.setProbeId(this.getRes().getProbeId());
                member.setRes(newRes);
                int index = 3;
                for (Attribute attr : attributes) {
                    Long attrId = attr.getId();
                    ResAttrVal change = new ResAttrVal();
                    change.setAttrId(attrId);
                    change.setAttrValue(result[index]);
                    member.getChangeAttrValues().add(change);
                    index++;
                }
                children.add(member);
            } else {// modify, existed is not null
                Long resId = existed.getRes().getId();
                int index = 3;
                for (Attribute attr : attributes) {
                    Long attrId = attr.getId();
                    ResAttrVal val = resAttrValCache.get(resId, attrId);
                    if (val == null || !val.getAttrValue().equals(result[index])) {
                        ResAttrVal change = new ResAttrVal();
                        change.setAttrId(attrId);
                        change.setAttrValue(result[index]);
                        existed.getChangeAttrValues().add(change);
                    }
                    index++;
                }
                if (existed.getChangeAttrValues().size() > 0) {
                    existed.setChanged(true);
                    existed.setChangeType(CHANGE_MOD);
                }
            }
        }
        for (FindResBean member : brothers) {
            boolean delted = true;
            for (String[] result : results) {
                if (result[0].equals(member.getRes().getInternalId())) {
                    delted = false;
                    break;
                }
            }
            if (delted) {
                member.setChanged(true);
                member.setChangeType(CHANGE_DEL);
            }
        }
    }

    public String toChangedString() {
        StringBuilder strBuilder = new StringBuilder();
        if (changeType == CHANGE_ADD) {
            strBuilder.append("名称:").append(res.getName()).append(";");
            strBuilder.append("描述:").append(res.getDesc()).append(";");
            strBuilder.append("唯一标示:").append(res.getInternalId()).append(";");
            for (ResAttrVal attrVal : changeAttrValues) {
                Long attrId = attrVal.getAttrId();
                String attrName = attributeCache.get(attrId).getName().trim();
                strBuilder.append(attrName).append(":").append(attrVal.getAttrValue()).append(";");
            }
        } else if (changeType == CHANGE_DEL) {
            strBuilder.append("ID:").append(res.getId()).append(";");
            strBuilder.append("名称:").append(res.getName()).append(";");
            strBuilder.append("描述:").append(res.getDesc()).append(";");
        } else if (changeType == CHANGE_MOD) {
            for (ResAttrVal attrVal : changeAttrValues) {
                Long attrId = attrVal.getAttrId();
                String attrName = attributeCache.get(attrId).getName().trim();
                ResAttrVal oldVal = resAttrValCache.get(res.getId(), attrId);
                String oldValue = oldVal == null ? "空" : oldVal.getAttrValue();
                strBuilder.append(attrName).append(":").append(oldValue).append(" 变为 ").append(attrVal.getAttrValue()).append(";");
            }
        }
        return strBuilder.toString();
    }

    private List<Attribute> getAttributes(Long resTypeId, String argAttr) {
        List<Attribute> resTypeAttributes = ResTypeBean.get(resTypeId).attributes();
        if (argAttr == null || argAttr.length() == 0) {
            return resTypeAttributes;
        } else {
            List<Attribute> attributes = new ArrayList<Attribute>();
            String[] attrIds = argAttr.split(",");
            for (int i = 0; i < attrIds.length; i++) {
                Long id = Long.parseLong(attrIds[i]);
                Attribute attr = attributeCache.get(id);
                if (resTypeAttributes.contains(attr)) {
                    attributes.add(attr);
                }
            }
            return attributes;
        }
    }
}
